<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>浅拷贝&深拷贝</title>
</head>

<body>
    <p>
        1.1 浅拷贝（Shallow Copy）<br>
        浅拷贝是指创建一个新对象，然后将原对象的属性值逐一复制到新对象中。
        但是，如果原对象的属性值是引用类型（如数组、对象等），那么浅拷贝只会复制引用地址，
        而不会复制引用类型的值。因此，当修改新对象中的引用类型值时，
        原对象中的引用类型值也会被修改，它们之间仍然存在相互影响的问题。

    </p>
    <p>
        实现浅拷贝的方法：<br>
        1、Object.assign()方法可以将一个或多个源对象的属性值复制到目标对象。<br>
        2、使用扩展运算符...可以将一个对象的所有属性值复制到另一个对象中。

    </p>
    <p>
        1.2 深拷贝（Deep Copy）<br>
        深拷贝是指创建一个新对象，然后递归地将原对象的属性值复制到新对象中。
        对于引用类型的属性值，深拷贝会创建一个新的引用类型并将其值复制过来，
        而不是简单地复制引用地址。因此，修改新对象中的引用类型值时，
        原对象中的引用类型值不会受到影响，它们之间不存在相互影响的问题。

    </p>
    <p>
        实现深拷贝的方法： <br>
        1 递归实现 。对于每个属性值，如果是基本数据类型，则直接复制；如果是引用类型，则递归地进行深拷贝。<br>
        2、使用JSON.stringify()方法将对象转换为JSON字符串，然后使用 JSON.parse() 方法将 JSON 字符串解析为新的对象，这样也可以实现深拷贝。但是，这种方法有一些局限性，例如它不能处理函数和
        undefined。<br>
        3、使用lodash库 的cloneDeep方法
    </p>
    <p>
        总结: <br>
        浅拷贝只复制对象的第一层属性，对于对象属性的引用类型，浅拷贝后两个对象会共享这部分内存。
        深拷贝会复制对象的所有层级，创建一个完全独立的新对象，新对象和原对象之间没有任何共享/引用的关系。
        在选择拷贝方式时，需要根据具体的需求和对象的复杂度来决定使用浅拷贝还是深拷贝。
    </p>

    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
    <script>
        // 浅拷贝
        let person = {
            name: '杨院长',
            status: '身体不适',
            love: {
                game: ['命运', '王者', '原神'],
                wanju: ['电棒', '四驱车', '娃娃']
            }
        }
        let newperson = {
            ...person
        }
        newperson.name = '周波喵喵'
        // newperson.love = '黑悟空' // 把整个属性的值改了，而不是改掉属性引用的值
        newperson.love.game = '卡丁车'
        newperson.love.yyy = '洗澡'
        newperson.love.wanju.push('键盘')
        console.log('person', person);
        console.log('newperson', newperson);

        // Object.assign()方法可以将一个或多个源对象的属性值复制到目标对象。
        // 它会对源对象的属性值进行浅拷贝
        let obj1 = {
            a: 1,
            b: [1, 2, 3]
        }
        let obj2 = Object.assign({}, obj1)
        obj2.b[0] = 99
        console.log(obj1);
        console.log(obj2);
        console.log(obj1.b === obj2.b); // true 原对象obj1被改变了

        // 使用扩展运算符...可以将一个对象的所有属性值复制到另一个对象中。
        // 这也是一种浅拷贝。
        let obj3 = {
            a: 1,
            b: [1, 2, 3]
        }
        let obj4 = { ...obj3 }
        obj3.b[0] = 888
        console.log(obj3);
        console.log(obj4);
        console.log(obj3.b === obj4.b); // true 说明原对象受到了影响

        let obj11 = { a: 1, b: [2, 3, 4] }
        const obj22 = { ...obj11 }


        // 深拷贝
        let personA = {
            name: '杨院长',
            status: '身体不适',
            love: {
                game: ['命运2'],
                wanju: ['四驱车']
            }
        }

        let newpersonA = {

        }

        // 1.递归实现
        function deepCopy(obj) {
            if (typeof obj !== 'object' || obj === null) {
                return obj
            }
            let result = Array.isArray(obj) ? [] : {}
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    result[key] = deepCopy(obj[key])
                }
            }
            return result
        }
        let obj5 = {
            a: 1,
            b: [1, 2, 3]
        };
        let obj6 = deepCopy(obj5)
        obj6.b[0] = 999
        console.log(obj5.b);
        console.log(obj6.b);
        console.log(obj5.b === obj6.b);  // false  说明原对象没有受到影响


        // 2.JSON.stringify() 和 JSON.parse()
        let obj7 = {
            a: 1,
            b: [1, 2, 3],
            c: function () { },
            d: undefined
        }
        let obj8 = JSON.parse(JSON.stringify(obj7))
        console.log(obj7.c); // ƒ () { }
        console.log(obj8.c); // 输出 undefined， 因为函数不能被 JSON.stringify()处理
        console.log(obj8.d); // undefined 因为 undefined不能被 JSON.stringify()处理


        // json方法强制转换
        const obj10 = {
            uname: 'pink',
            age: 18,
            hobby: ['乒乓球', '足球'],
            family: {
                baby: '小pink'
            }
        }
        // 把对象转换为 JSON 字符串
        // console.log(JSON.stringify(obj))
        const o2 = JSON.parse(JSON.stringify(obj10))
        console.log(o2)
        o2.family.baby = '123'
        console.log(o2); // {baby: '123'}
        console.log(obj10) // {baby: '小pink'}



        // 3.使用lodash库 的cloneDeep方法
        const obj9 = {
            uname: 'pink',
            age: 18,
            hobby: ['兵乓球', '足球'],
            family: {
                baby: '小pink'
            }
        }
        const o = _.cloneDeep(obj9)
        console.log(o);
        o.family.baby = '大baby'
        console.log(o);
        console.log(obj9);
        console.log(o === obj9); // false 实现了深拷贝，两个对象互不影响



    </script>
</body>

</html>